// URL 处理工具
import { isDate, isPlainObject, isURLSearchParams } from "./util"

interface URLOrigin {
  protocol: string
  host: string
}

function encode(val: string): string {
  return encodeURIComponent(val)
    .replace(/%40/g, '@') //（保留 @ 符号，避免被编码）
    .replace(/%3A/ig, ':')
    .replace(/%24/g, '$')
    .replace(/%2C/ig, ',')
    .replace(/%20/g, '+')
    .replace(/%5B/ig, '[')
    .replace(/%5D/ig, ']')
}

//  构建完整 URL 
export function buildURL(
  url: string,
  params?: any,
  paramsSerializer?: (params: any) => string): string {
  if (!params) {
    return url
  }

  let serializedParams

  if (paramsSerializer) {
    serializedParams = paramsSerializer(params) // 用户自定义处理（最高优先级）
  } else if (isURLSearchParams(params)) {
    serializedParams = params.toString() // 浏览器原生参数对象（次优先级）
  }
  else {
    const parts: string[] = [] // 用于存储编码后的键值对. 比如parts 数组变为 ['name=John', 'age=25', 'hobbies[]=reading', 'hobbies[]=swimming']

    // 遍历参数对象的所有键
    Object.keys(params).forEach((key) => {
      const val = params[key]
      // 跳过值为 null 或 undefined 的参数（不添加到 URL 中）
      if (val === null || typeof val === 'undefined') {
        return
      }

      let values = []  // 存储参数值
      // 数组参数：转换为 key[]=val1&key[]=val2 格式（如 ids[]=1&ids[]=2），符合 RESTful API 规范。
      if (Array.isArray(val)) {
        // 直接将数组赋值给 values
        values = val
        // 对于数组类型的参数，按照 RESTful API 规范，键名后面添加 []
        key += '[]'
      } else {
        values = [val]
      }

      values.forEach((val) => {
        // 如果是日期类型，转换为 ISO 字符串
        if (isDate(val)) {
          val = val.toISOString()
        }// 如果是对象类型，转换为 JSON 字符串（如 { "id": 1 } → %7B%22id%22%3A1%7D）
        else if (isPlainObject(val)) {
          val = JSON.stringify(val)
        }  // 对键和值分别编码，并拼接为 "key=value" 格式，添加到 parts 数组
        parts.push(`${encode(key)}=${encode(val)}`)
      })
    })
    // 拼接所有键值对为完整的查询字符串（如 "page=1&name=John"）
    serializedParams = parts.join('&')
  }

  if (serializedParams) {// 如果有查询参数需要添加
    // 处理 URL 中的锚点（# 后面的部分，如 #section1），先移除锚点再添加参数
    const markIndex = url.indexOf('#')
    if (markIndex !== -1) {
      url = url.slice(0, markIndex)// 截取锚点前的 URL 部分
    }
    // 判断 URL 是否已有问号，决定添加 & 还是 ? 作为参数分隔符
    url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams
  }
  return url
}

// 判断 URL 是否为绝对路径
export function isAbsoluteURL(url: string): boolean {
  return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url)
}

export function combineURL(baseURL: string, relativeURL?: string): string {
  return relativeURL ?
    baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')  // baseURL 移除末尾多余斜杠（如 http://api.com/ → http://api.com），relativeURL 移除开头多余斜杠（如 /user/ → user）
    : baseURL
}

// 同源判断
export function isURLSameOrigin(requestURL: string): boolean {
  const parsedOrigin = resolveURL(requestURL)
  return (
    parsedOrigin.protocol === currentOrigin.protocol &&
    parsedOrigin.host === currentOrigin.host)
}

const urlParsingNode = document.createElement('a')// 使用浏览器原生解析能力
const currentOrigin = resolveURL(window.location.href)// 当前页面的源

function resolveURL(url: string): URLOrigin {
  urlParsingNode.setAttribute('href', url) // 浏览器自动解析 URL
  const { protocol, host } = urlParsingNode // 获取协议（如 http:）和主机（如 api.com）

  return { protocol, host }
}